package com.oj.util;

import com.oj.config.OJConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.system.ApplicationHome;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

@Slf4j
public class Hex2Pcap {
    public static String convertToHtml(String text) {
        List<String> listItems = new ArrayList<>();
        String[] lines = text.split("\n");
        int lastIndent = 0;
        int index = 1;
        for (String line : lines) {
            String new_line = "";
            int lineIndent = countLeadingSpaces(line)/4;

            String liClass = "item-packet";
            if (lineIndent == 0) {
                liClass += " root-item-packet";
            }
            if (lineIndent < lastIndent) {
                /* end child leaf */
                String prefixUlEnd = "";
                for (int i = 0; i < lastIndent - lineIndent; i++) {
                    prefixUlEnd += "</ul></li>";
                }
                new_line = prefixUlEnd + "<li class='"+liClass+"' id='"+index+"' level="+ lineIndent + "'>"  + line.trim();
            } else if (lineIndent > lastIndent) {
                /* new child leaf */
                String prefixUl = "";
                for (int i = 0; i < lineIndent - lastIndent; i++) {
                    prefixUl += "<ul class='item-packets' level="+ lastIndent + "'>";
                }
                new_line = prefixUl + "<li class='"+liClass+"' id='"+index+"' level="+ lineIndent + "'>"  + line.trim();
            } else {
                /* new brother leaf */
                if (listItems.size() > 0) {
                    new_line = "</li>";
                }

                new_line += "</li><li class='"+liClass+"' id='"+index+"' level="+ lineIndent + "'>"  + line.trim();
            }
            listItems.add(new_line);
            lastIndent = lineIndent;
            index++;
        }

        return "<ul>\n" + String.join("\n", listItems) + "\n</ul>";
    }

    private static int countLeadingSpaces(String s) {
        int count = 0;
        while (count < s.length() && s.charAt(count) == ' ') {
            count++;
        }
        return count;
    }

    private static String getProcessOutput(InputStream fis){
        try {
            InputStreamReader isr=new InputStreamReader(fis,"utf-8");
            BufferedReader br=new BufferedReader(isr);
            String result = "";
            String line = null;
            while((line = br.readLine()) != null) {
                result += line + "\n";
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    private static String hexStringDump(String hex){
        final int perRow = 32;

        String pktFmt = "";
        hex = hex.replaceAll(" ", "");
        for (int i = 0; i < hex.length();) {
            int offset = i % perRow;
            if (offset == 0) {
                pktFmt += String.format("%06x", i/2);
                pktFmt += " ";
            }
            pktFmt += hex.charAt(i);
            i++;
            if (i < hex.length()) {
                pktFmt += hex.charAt(i);
                i++;
                pktFmt += " ";
            }

            if (i % perRow == 0) {
                pktFmt += "\n";
            }
        }
        if (hex.length() % perRow != 0) {
            pktFmt += "\n";
        }
        pktFmt += String.format("%06x", hex.length()/2);

        log.info("\n" + pktFmt);
        return pktFmt;
    }

    public static String hex2Pcap(String hex, String type) {
        try {
            ApplicationHome h = new ApplicationHome(Hex2Pcap.class);
            if (h == null || h.getSource() == null || h.getSource().getParentFile() == null) {
                return "";
            }
            String dirPath1 = h.getSource().getParentFile().toString()+"/data/";
            File file = new File(dirPath1);
            if (!file.exists()) {
                if (file.mkdir()) {
                }else{
                    log.error(dirPath1 + " create failed.");
                }
            }

            SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
            String sessionId = df.format(new Date()) + MD5Util.MD5(df.format(new Date())+ new Random().nextInt(1000)).toString();

            String input = dirPath1 + sessionId + ".txt";
            String pcap = dirPath1 + sessionId + ".pcap";
            StreamHandler.write(input, hexStringDump(hex));

            String typePkt = "";
            if (type != null) {
                // -E rawip4 rawip6
                // -e 0800
                typePkt = "-e " + type;
            }
            String command = OJConfig.getWiresharkPath() + "text2pcap -o hex "+ input + " "+ pcap + " " + typePkt;
            log.info(command);
            Process process = Runtime.getRuntime().exec(command, null, file);
            process.waitFor();

            File fileTxt = new File(input);
            fileTxt.delete();

            if (!new File(pcap).exists()) {
                log.error("text2pcap failed.");
                return null;
            }
            return pcap;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    public static String PacketDumpHex(String pcap) {
        try {
            String command = OJConfig.getWiresharkPath() + "tshark -r " + pcap + " -x";
            log.info(command);
            Process process = Runtime.getRuntime().exec(command);
            String hexdump = getProcessOutput(process.getInputStream());
            process.waitFor();
            return hexdump;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "";
    }
    public static String PacketDumpVerbose(String pcap) {
        try {
            String command = OJConfig.getWiresharkPath() + "tshark -r " + pcap;
            log.info(command);
            Process process = Runtime.getRuntime().exec(command);
            String verbose = getProcessOutput(process.getInputStream()).trim().replaceAll("\\s+", " ");
            process.waitFor();
            int firstSpace = verbose.indexOf(" ");
            int secondSpace = verbose.indexOf(" ", firstSpace + 1);
            verbose = verbose.substring(secondSpace, verbose.length());
            return verbose.trim();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "";
    }
    public static String PacketDumpDetails(String pcap) {
        try {
            String command = OJConfig.getWiresharkPath() + "tshark -V -r " + pcap ;
            log.info(command);
            Process process = Runtime.getRuntime().exec(command);
            String result = getProcessOutput(process.getInputStream());
            process.waitFor();
            return convertToHtml(result);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    public static String PacketDumpXML(String pcap) {
        try {
            String command = OJConfig.getWiresharkPath() + "tshark -r " + pcap + " -T pdml ";
            log.info(command);
            Process process = Runtime.getRuntime().exec(command);
            String result = getProcessOutput(process.getInputStream());
            process.waitFor();
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "";
    }
    public static void main(String[] args) throws IOException {
        String pkt = "01005e00000ac20173fe0000080045c0003c000000000258cd9f0a000001e000000a0205ee68000000000000000000000000000000640001000c010001000000000f000400080c040102";
        String pkt2 = "01005e00000ac20173fe0000080045c0";
        //hexStringDump(pkt2);
        //log.info(hexPacketDump(pkt));
        return;
    }
}
